// These are meant to be typed into the REPL. You can also run
// scala -Xnojline < repl-session.scala to run them all at once.

/*class Pair[T](val first: T, val second: T) {
  def smaller = if (first.compareTo(second) < 0) first else second // Error
}*/
/**
  * 13.3类型变量限定
  *
  * 在 Java 泛型里表示某个类型是 Test 类型的子类型， 使用 extends 关键
  * 字：
  *
  * <T extends Test>
  * //或用通配符的形式：
  * <? extends Test>
  * 这种形式也叫为上限或上界， 同样的意思在 scala 的写法为：
  * [T <: Test]
  * 需要用<:来表示，叫做上界。上界： 类型参数应该是某某的子类型。
  * //或用通配符: [_ <: Test]
  *
  */

class Pair1[T <: Comparable[T]](val first: T, val second: T) {
  def smaller = if (first.compareTo(second) < 0) first else second
}

val p = new Pair1("Fred", "Brooks")
println(p.smaller)

val pe = new Pair(4, 2) // Won't work--see Section 17.4 for a remedy
//println(pe.smaller)

/**
  * 在 Java 泛型里表示某个类型是 Test 类型的父类型，
  * 使用 super 关键字：
  * <T super Test>
  * //或用通配符的形式：
  * <? super Test>
  * 这种形式也叫下限或下界，同样的意思在 scala 的写法为：
  * [T >: Test]
  * //或用通配符: [_ >: Test]
  */
class Pair2[T](val first: T, val second: T) {
  def replaceFirst[R >: T](newFirst: R) = new Pair(newFirst, second)
  override def toString = "(" + first + "," + second + ")"
}

class Person1(name: String) {
  override def toString = getClass.getName + " " + name
}

class Student1(name: String) extends Person1(name)

val fred = new Student1("Fred")
val wilma = new Student1("Wilma")
val barney = new Person1("Barney")

val p1 = new Pair2(fred, wilma)
p1.replaceFirst(barney) // A Pair[Person]

// Don't omit the upper bound:

class Pair3[T](val first: T, val second: T) {
  def replaceFirst[R](newFirst: R) = new Pair(newFirst, second)
  override def toString = "(" + first + "," + second + ")"
}

val p2 = new Pair3(fred, wilma)
p2.replaceFirst(barney) // A Pair[Any]

/**
  * Java 里，T  同时是 A   和 B   的子类型，称为 multiple bounds
  * <T extends A &  B>
  * Scala 里对上界和下界不能有多个，不过变通的做法是使用复合类型
  * (compund type):
  * [T <: A with  B]
  * 而对于下界，在 java 里则不支持 multiple bounds 的形式:
  * <T super A & B> //java  不支持
  * Scala 里对复合类型同样可以使用下界
  * [T >: A with  B]
  * 因为 Scala 里对于 A with B 相当于 (A with B)，仍看成一个类型，
  */

